package com.wits100.av;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.view.Surface;

import java.nio.ByteBuffer;

/**
 * Created by chuanjiang.zh on 2016-08-15.
 */
public class DirectVideoRender implements VideoRender {


    @Override
    public boolean open(MFormat fmt, Surface surface) {
        synchronized (this) {
            mFormat = fmt;
            mSurface = surface;

            return openCodec();
        }
    }

    @Override
    public void close() {
        closeCodec();
    }

    @Override
    public boolean isOpen() {
        return isCodecOpen();
    }

    @Override
    public void setDisplay(Surface surface) {
        synchronized (this) {
            if (mSurface == surface) {
                //
            } else {
                mSurface = surface;

                openCodec();
            }
        }
    }

    @Override
    public void input(MPacket pkt) {

        synchronized (this) {
            if (mSurface == null) {
                return;
            }

            if (!isCodecOpen()) {
                return;
            }

            doInput(pkt);

            doRender();
        }

    }


    private void doInput(MPacket pkt) {
        final int TIMEOUT_USEC = 10 * 1000;
        ByteBuffer[] decoderInputBuffers = mCodec.getInputBuffers();
        int inputBufIndex = mCodec.dequeueInputBuffer(TIMEOUT_USEC);
        if (inputBufIndex >= 0) {
            ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex];
            inputBuf.put(pkt.data);
            mCodec.queueInputBuffer(inputBufIndex, 0, pkt.length(),
                    pkt.ts, pkt.flags);

        }
    }

    private void doRender() {
        int ret = mCodec.dequeueOutputBuffer(mBufferInfo, 0);
        if (ret == MediaCodec.INFO_TRY_AGAIN_LATER) {

        } else if (ret == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {

        } else if (ret == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {

        } else if (ret >= 0) {
            mCodec.releaseOutputBuffer(ret, true);
        }

    }


    private boolean openCodec() {
        closeCodec();

        if (mSurface == null) {
            return false;
        }

        try {
            mediaFormat = mFormat.toVideoFormat();
            String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
            mCodec = MediaCodec.createDecoderByType(mime);
            mCodec.configure(mediaFormat, mSurface, null, 0);
            mCodec.start();
            return true;
        } catch (Throwable e) {
            if (mCodec != null) {
                mCodec.release();
                mCodec = null;
            }

            e.printStackTrace();
        }
        return false;
    }

    private void closeCodec() {
        if (mCodec != null) {
            try {
                mCodec.stop();
                mCodec.release();
            } finally {
                mCodec = null;
            }
        }
    }

    private boolean isCodecOpen() {
        return mCodec != null;
    }


    MFormat mFormat;
    MediaCodec mCodec;
    Surface mSurface;
    MediaFormat mediaFormat;

    private MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();

}
